from sklearn import tree
from sklearn.datasets import load_wine
from sklearn.model_selection import train_test_split

wine=load_wine()
# sklearn.datasets里面的数据集都是字典类型
print(wine.keys())
# print(wine.DESCR)

# 拆分训练集和测试集
x_train,x_test,y_train,y_test=train_test_split(wine.data,wine.target,test_size=0.3)

"""
树模型在分支的时候会计算每个节点的不纯度。衡量不纯度的指标有信息熵和基尼系数两种。
max_depth是指决策树的深度，有几层。可以控制过拟合。
"""

clf=tree.DecisionTreeClassifier(criterion='entropy'
                                ,random_state=30    # 确定随机性，调参过程中使用
                                ,splitter="random"  # 添加后可以防止过拟合
                                ,max_depth=3
                                ,min_samples_leaf=5
                                # ,min_samples_split=
                                )
clf=clf.fit(x_train,y_train)
score=clf.score(x_test,y_test)
print('测试集score',score)

# 决策树可视化    jupyter下面可以显示决策树
# import graphviz
# dot_data=tree.export_graphviz(clf
#                               ,feature_names=wine.feature_names
#                               ,class_names=['a_wine','b_wine','c_wine']
#                               ,filled=True
#                               ,rounded=True
#                               )
# graph=graphviz.Source(dot_data)
# graph

# feature_importances_
# clf.feature_importances_  可以显示不同特征的重要性，数值越高越重要
print([*zip(wine.feature_names,clf.feature_importances_)])  # 注意zip的用法

score2=clf.score(x_train,y_train)
print('训练集score',score2)
"""
当训练集得分高，测试集得分低时，说明模型过拟合了
为了让决策树有更好的泛化性，就要对决策树进行剪枝
剪枝参数  通过剪枝控制过拟合，控制树的复杂性和大小
max_depth 树的最大深度，最常用，高纬度低样本数据非常有效，通常从3开始
min_samples_leaf  如果一个节点在分支后的子节点的样本量小于min_samples_leaf时，分支不会发生，或者分支会朝着每个子节点都包含min_samples_leaf个子节点的方向分支。通常从5开始使用
min_samples_split 一个节点必须包含min_samples_split个训练样本，否则不允许分支
"""

# 参数学习曲线
import matplotlib.pyplot as plt
test=[]
for i in range(10):
    clf = tree.DecisionTreeClassifier(criterion='entropy'
                                      , random_state=30  # 确定随机性，调参过程中使用
                                      , splitter="random"  # 添加后可以防止过拟合
                                      , max_depth=i+1
                                      )
    clf = clf.fit(x_train, y_train)
    score3 = clf.score(x_test, y_test)
    test.append(score3)
print(test)
plt.plot(range(1,11),test,color="red",label="max_depth")
plt.legend()
plt.show()

# 其他重要方法
# clf.apply(x_test)   返回每个测试样本所在叶子节点的索引
# clf.predict(x_test)   返回每个测试样本的分类/回归结果